#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
@File    : dingtalk_handler.py
@Description : 钉钉通知模块，用于发送测试结果通知到钉钉群
'''

import os
import time
import hmac
import hashlib
import base64
import urllib.parse
from typing import Dict, List, Any, Optional, Union
from datetime import datetime

from dingtalkchatbot.chatbot import DingtalkChatbot

# 导入配置和日志
from config.settings import config
from utils.log_handler import get_logger


class DingTalkHandler:
    """
    钉钉通知类，用于发送测试结果通知到钉钉群
    """
    def __init__(self, webhook: str = None, secret: str = None):
        """
        初始化钉钉通知类
        
        Args:
            webhook: 钉钉机器人webhook地址，默认为None，使用配置文件中的webhook
            secret: 钉钉机器人安全设置的密钥，默认为None，使用配置文件中的密钥
        """
        self.logger = get_logger("dingtalk_handler")
        
        # 如果未指定webhook和secret，使用配置文件中的值
        self.webhook = webhook or config.dingtalk_webhook
        self.secret = secret or config.dingtalk_secret
        
        # 创建钉钉机器人实例
        try:
            self.robot = DingtalkChatbot(self.webhook, secret=self.secret)
            self.logger.info("钉钉机器人初始化成功")
        except Exception as e:
            self.logger.error(f"钉钉机器人初始化失败: {str(e)}")
            self.robot = None
    
    def _generate_sign(self) -> str:
        """
        生成钉钉机器人签名
        
        Returns:
            签名字符串
        """
        timestamp = str(round(time.time() * 1000))
        secret_enc = self.secret.encode('utf-8')
        string_to_sign = f'{timestamp}\n{self.secret}'
        string_to_sign_enc = string_to_sign.encode('utf-8')
        hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
        sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
        return f"&timestamp={timestamp}&sign={sign}"
    
    def send_text(self, content: str, at_mobiles: List[str] = None, at_all: bool = False) -> bool:
        """
        发送文本消息
        
        Args:
            content: 消息内容
            at_mobiles: 需要@的手机号列表
            at_all: 是否@所有人
            
        Returns:
            发送结果，True表示成功，False表示失败
        """
        if not self.robot:
            self.logger.error("钉钉机器人未初始化，无法发送消息")
            return False
        
        try:
            self.robot.send_text(msg=content, at_mobiles=at_mobiles, is_at_all=at_all)
            self.logger.info("钉钉文本消息发送成功")
            return True
        except Exception as e:
            self.logger.error(f"钉钉文本消息发送失败: {str(e)}")
            return False
    
    def send_markdown(self, title: str, text: str, at_mobiles: List[str] = None, at_all: bool = False) -> bool:
        """
        发送markdown消息
        
        Args:
            title: 消息标题
            text: markdown格式的消息内容
            at_mobiles: 需要@的手机号列表
            at_all: 是否@所有人
            
        Returns:
            发送结果，True表示成功，False表示失败
        """
        if not self.robot:
            self.logger.error("钉钉机器人未初始化，无法发送消息")
            return False
        
        try:
            self.robot.send_markdown(title=title, text=text, at_mobiles=at_mobiles, is_at_all=at_all)
            self.logger.info("钉钉markdown消息发送成功")
            return True
        except Exception as e:
            self.logger.error(f"钉钉markdown消息发送失败: {str(e)}")
            return False
    
    def send_link(self, title: str, text: str, message_url: str, pic_url: str = None) -> bool:
        """
        发送链接消息
        
        Args:
            title: 消息标题
            text: 消息内容
            message_url: 点击消息跳转的URL
            pic_url: 图片URL
            
        Returns:
            发送结果，True表示成功，False表示失败
        """
        if not self.robot:
            self.logger.error("钉钉机器人未初始化，无法发送消息")
            return False
        
        try:
            self.robot.send_link(title=title, text=text, message_url=message_url, pic_url=pic_url)
            self.logger.info("钉钉链接消息发送成功")
            return True
        except Exception as e:
            self.logger.error(f"钉钉链接消息发送失败: {str(e)}")
            return False
    
    def send_test_report(self, total: int, passed: int, failed: int, skipped: int, 
                         duration: float, report_url: str = None) -> bool:
        """
        发送测试报告
        
        Args:
            total: 总用例数
            passed: 通过用例数
            failed: 失败用例数
            skipped: 跳过用例数
            duration: 测试耗时（秒）
            report_url: 测试报告URL
            
        Returns:
            发送结果，True表示成功，False表示失败
        """
        # 计算通过率
        pass_rate = round(passed / total * 100, 2) if total > 0 else 0
        
        # 构建markdown消息
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        title = f"接口自动化测试报告 - {now}"
        
        # 根据通过率设置状态图标
        if pass_rate >= 90:
            status_icon = "✅"
        elif pass_rate >= 80:
            status_icon = "⚠️"
        else:
            status_icon = "❌"
        
        text = f"## {status_icon} 接口自动化测试报告 - {now}\n\n"
        text += f"### 测试结果概览\n\n"
        text += f"- **总用例数**: {total}\n"
        text += f"- **通过用例数**: {passed}\n"
        text += f"- **失败用例数**: {failed}\n"
        text += f"- **跳过用例数**: {skipped}\n"
        text += f"- **通过率**: {pass_rate}%\n"
        text += f"- **测试耗时**: {round(duration, 2)}秒\n\n"
        
        # 如果有报告URL，添加报告链接
        if report_url:
            text += f"### 详细报告\n\n"
            text += f"[点击查看详细测试报告]({report_url})\n\n"
        
        # 添加时间戳
        text += f"\n> 测试时间: {now}\n"
        
        # 发送markdown消息
        return self.send_markdown(title=title, text=text, at_all=failed > 0)


if __name__ == '__main__':
    # 测试钉钉通知
    handler = DingTalkHandler()
    # 发送测试报告
    handler.send_test_report(
        total=10,
        passed=8,
        failed=1,
        skipped=1,
        duration=15.5,
        report_url="http://example.com/report"
    )